package svgedit.gui.command;

import java.util.ArrayList;
import java.util.HashMap;

import svgedit.gui.Frame;
import svgedit.svg.SVGElement;
import svgedit.svg.SVGGroup;

/**
 * Define ungroup execution as a command object which has 
 *      execute (redo) and undo methods
 */
public class UnGroupCommand implements Command{
	
	private Frame frame;
	@SuppressWarnings("unchecked")
	private HashMap parents = new HashMap();
	@SuppressWarnings("unchecked")
	private HashMap map = new HashMap();
	private ArrayList<SVGElement> elements = new ArrayList<SVGElement>();
	
	/**
	 *  Constructor for ungroup command
	 *  
	 *  @param frame to get the frame object
	 * */
	public UnGroupCommand(Frame frame){
		this.frame = frame;
	}
	
	/**
	 *   Execute to ungroup selected elements or redo to ungroup these elements
	 * */
	@SuppressWarnings("unchecked")
	public void execute(){
		// New selection will be previous selection, plus all children
        // that were ungrouped
        ArrayList<SVGElement> selection = new ArrayList<SVGElement>();

		 if(map.size() == 0){
			 SVGElement elems[] = frame.getView().getSelectedElements();
		        // Find currently selected groups
		        for (SVGElement elem : elems) {
		        	elements.add(elem);
		            if (elem instanceof SVGGroup) {
		                // Remove children from group, add to document root
		                // TODO: Z-ordering is broken by this operation;
		                //   children should be inserted where the group was
		                SVGElement[] children = ((SVGGroup) elem).getChildren();
		                // Backup group and its children
		                map.put(elem, children);
		                for (SVGElement child : children) {
		                    child.getParent().removeChild(child);
		                    frame.getDocument().getRootGroup().appendChild(child);
		                    selection.add(child);
		                }
                        // Backup group and its parent
		                parents.put(elem, elem.getParent());
		                // Remove group
		                elem.getParent().removeChild(elem);
		            } else {
		                selection.add(elem);
		            }
		        }

		 }else {
			 for (SVGElement elem : elements){
				 if(elem instanceof SVGGroup){
					 if(map.containsKey(elem)){
						 SVGElement[] children = (SVGElement[])map.get(elem);
						 for (SVGElement child : children){
							 child.getParent().removeChild(child);
			                 frame.getDocument().getRootGroup().appendChild(child);
			                 selection.add(child);
						 }
						 
						 // Remove group
			                elem.getParent().removeChild(elem); 
					 }
				 }else {
		                selection.add(elem);
		         }
			 }
		 }
		 frame.getView().getDocument().setModified(true);
	     frame.getView().setSelectedElements(selection.toArray(new SVGElement[0])); 
		 
	}
	
	/**
	 *   After ungrouping selected elements, recover all these elements to their original statue
 	 * */
	public void undo(){
		for (int i = 0; i < elements.size(); i++){
			if (elements.get(i) instanceof SVGGroup){
				if (map.containsKey(elements.get(i))){
					 SVGElement[] children = (SVGElement[])map.get(elements.get(i));
					 // Add children to their original group
					 for (SVGElement child : children){
						 frame.getDocument().getRootGroup().removeChild(child);
						 ((SVGGroup)elements.get(i)).appendChild(child);
					 }
					 // Add group to its original parent
					 if (parents.containsKey(elements.get(i))){
						 ((SVGGroup)parents.get(elements.get(i))).appendChild(elements.get(i));
					 }
				}
				
			}
		}
		frame.getView().clearSelection();
		
	}

}
